#ifndef SPARSE_MARTRIX_H_

#define SPARSE_MARTRIX_H_

#include <iostream>
#include "status.h"
using namespace std;

template<typename T>
class Martrix
{
private:
	struct Triple
	{
		int i, j;
		T data;
	};

	Triple * base;
	int * num;
	int * cpot;
	int mu, nu, tu;
public:
	Martrix(): base(nullptr), num(nullptr), cpot(nullptr), mu(0), nu(0), tu(0) {}
	Status CreateMartrix(const Triple * b, int m, int n, int t);
	Martrix(const Martrix<T> & N);
	~Martrix();
	Status CreateMartrix();
	Status PrintMartrix() const;
	Status AddMartrix(const Martrix<T> & N, Martrix<T> & Q) const;
	Status SubMartrix(const Martrix<T> & N, Martrix<T> & Q) const;
	Status MultMartrix(const Martrix<T> & N, Martrix<T> & Q) const;
	Status TransposeMartrix() const;
	Status operator=(const Martrix<T> & N);
};

template<typename T>
Martrix<T>::Martrix(const Martrix<T> & N)
{
	this->base = new Triple[N.tu];
	this->num = new int[N.tu];
	this->cpot = new int[N.tu];
	this->mu = N.mu;
	this->nu = N.nu;
	this->tu = N.tu;
	for (int i = 0; i < this->tu; i++)
	{
		this->base[i] = N.base[i];
		this->num[i] = N.num[i];
		this->cpot[i] = N.cpot[i];
	}
}

template<typename T>
Status Martrix<T>::CreateMartrix(const Triple * b, int m, int n, int t)
{
	if (!this->base)
	{
		delete[] base;
		delete[] num;
		delete[] cpot;
	}
	base = new Triple[tu];
	num = new int[tu];
	cpot = new int[tu];
	mu = m, nu = n, tu = t;

	for (int i = 0; i < this->tu; i++)
		this->cpot[i] = 0;
	for (int i = 0; i < t; i++)
	{
		base[i] = b[i];
		++cpot[base[i].j];
	}
	int count = this->cpot[0];
	this->num[0] = 1;
	for (int i = 1; i < this->tu; i++)
	{
		this->num[i] = 1 + count;;
		count += this->cpot[i];
	}
	return OK;
}

template<typename T>
Martrix<T>::~Martrix()
{
	//delete[] base;
	//delete[] num;
	//delete[] cpot;
}

template<typename T>
Status Martrix<T>::CreateMartrix()
{
	cout << "input mu, nu, tu" << endl;
	cin >> this->mu >> this->nu >> this->tu;
	this->base = new Triple[this->tu];
	this->cpot = new int[this->tu];
	this->num = new int[this->tu];

	for (int i = 0; i < this->tu; i++)
		this->cpot[i] = 0;
	for (int i = 0; i < this->tu; i++)
	{
		cout << "input i, j, data" << endl;
		cin >> this->base[i].i >> this->base[i].j >> this->base[i].data;
		++cpot[this->base[i].j];
	}
	int count = this->cpot[0];
	this->num[0] = 1;
	for (int i = 1; i < this->tu; i++)
	{
		this->num[i] = 1 + count;;
		count += this->cpot[i];
	}
	return OK;
}

template<typename T>
Status Martrix<T>::PrintMartrix() const
{
	for (int i = 0; i < this->tu; i++)
		cout << base[i].i << " " << base[i].j << " " << base[i].data << endl;

	return OK;
}

template<typename T>
Status Martrix<T>::AddMartrix(const Martrix<T> & N, Martrix<T> & Q) const
{
	if (this->mu != N.mu || this->nu != N.nu)
		return ERROR;

	Triple * tmp = new Triple[this->tu + N.tu];
	int count = 0;
	int a = 0;
	int b = 0;
	while (a < this->tu && b < N.tu)
	{
		if (this->base[a].i < N.base[b].i || (base[a].i == N.base[b].i && base[a].j < N.base[b].j))
		{
			tmp[count] = this->base[a];
			++count;
			++a;
		}
		else if (this->base[a].i > N.base[b].i || (base[a].i == N.base[b].i && base[a].j > N.base[b].j))
		{
			tmp[count] = N.base[b];
			++count;
			++b;
		}
		else
		{
			tmp[count].i = base[a].i;
			tmp[count].j = base[a].j;
			tmp[count].data = base[a].data + N.base[b].data;
			++a;
			++b;
			++count;
		}
	}

	while (a < this->tu)
	{
		tmp[count] = base[a];
		++a;
		++count;
	}
	while (b < N.tu)
	{
		tmp[count] = N.base[b];
		++b;
		++count;
	}

	Q.CreateMartrix(tmp, this->mu, this->nu, count);

	return OK;
}



#endif